package org.hgf.testrabbitmq.consumer.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.hgf.testrabbitmq.consumer.service.IQueueService;
import org.hgf.testrabbitmq.utils.constants.Constants;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 队列服务具体实现
 *
 * @author 何国发
 * @version 1.0.0
 * @date 2022/9/7 17:31
 */
@Slf4j
@Service
public class QueueServiceImpl implements IQueueService {

    /**
     * 缓存连接工厂
     */
    @Resource
    private CachingConnectionFactory connectionFactory;

    /**
     * rabbi管理辅助操作类
     */
    @Resource
    private RabbitAdmin rabbitAdmin;

    /**
     * 获取mq中所有队列的名称
     *
     * @return java.util.List<java.lang.String>
     * @author 何国发
     * @date 2022/9/7 17:35
     */
    @Override
    public List<String> queueNameList() {
        // 调用rabbitmq内部的接口
        Map<String, Object> map = this.sendPost();
        CloseableHttpClient httpClient = (CloseableHttpClient) map.get("httpClient");
        CloseableHttpResponse response = (CloseableHttpResponse) map.get("response");

        // 校验调用状态
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == Constants.SUCCESS)
        {
            try {
                // 获取响应的http的正文消息
                String result = EntityUtils.toString(response.getEntity());
                // 转jsonArray
                JSONArray jsonArray = JSON.parseArray(result);
                if (jsonArray != null)
                {
                    List<String> queueNameList = new ArrayList<>();
                    for (int i = 0; i < jsonArray.size(); i++) {
                        // 获取队列的名称
                        String queueName = String.valueOf(jsonArray.getJSONObject(i).get("name"));
                        queueNameList.add(queueName);
                    }
                    log.info(String.valueOf(queueNameList));
                    return queueNameList;
                } else {
                    log.warn("数据为空");
                }
            } catch (Exception e) {
                log.error("调用rabbitmq内部接口出错，异常信息为：{}", e.getMessage());
                throw new RuntimeException("操作失败，调用rabbitmq内部接口出错！");
            } finally {
                // 关闭连接
                this.close(response, httpClient);
            }
        }
        // 关闭连接
        this.close(response, httpClient);

        log.error("请求rabbitmq内部接口失败，状态码：{}", statusCode);
        throw new RuntimeException("操作失败，调用rabbitmq内部接口出错！");
    }

    /**
     * 根据队列名称删除队列（队列没有使用及没有参数就删除）
     *
     * @param queueName 队列名称
     * @return java.lang.Boolean
     * @author 何国发
     * @date 2022/9/8 9:24
     */
    @Override
    public Boolean deleteQueue(String queueName) {
        return this.deleteByQueueName(queueName, false, true, true);
    }

    /**
     * 根据队列名称删除队列（强制删除）
     *
     * @param queueName         要删除的队列名称
     * @param forceDeleteFlag   是否强制删除标识，true：强制删除  false：不强制删除
     * @return java.lang.Boolean
     * @author 何国发
     * @date 2022/9/8 9:36
     */
    @Override
    public Boolean deleteQueue(String queueName, Boolean forceDeleteFlag) {
        return this.deleteByQueueName(queueName, forceDeleteFlag, false, false);
    }

    /**
     * 调用rabbitmq内部的接口
     *
     * @return org.apache.http.client.methods.CloseableHttpResponse
     * @author 何国发
     * @date 2022/9/7 18:02
     */
    private Map<String, Object> sendPost() {
        Map<String, Object> map = new HashMap<>(15);

        String url = Constants.HTTP + connectionFactory.getHost() + ":15672" + "/api/queues";
        HttpGet httpGet = new HttpGet(url);

        // 拼装验证参数
        CloseableHttpClient httpClient = this.getBasicHttpClient();
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpGet);
        } catch (IOException e) {
            e.printStackTrace();
        }
        map.put("response", response);
        map.put("httpClient", httpClient);

        return map;
    }

    /**
     * 获取 CloseableHttpClient
     *
     * @return org.apache.http.impl.client.CloseableHttpClient
     * @author 何国发
     * @date 2022/9/7 17:46
     */
    private CloseableHttpClient getBasicHttpClient() {
        // 创建HttpClientBuilder
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();

        // 设置BasicAuth
        CredentialsProvider provider = new BasicCredentialsProvider();
        AuthScope scope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM);
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(connectionFactory.getUsername(), connectionFactory.getRabbitConnectionFactory().getPassword());
        provider.setCredentials(scope, credentials);
        httpClientBuilder.setDefaultCredentialsProvider(provider);

        return httpClientBuilder.build();
    }

    /**
     * 关闭资源
     *
     * @param response      响应消息
     * @param httpClient    http客户端
     * @author 何国发
     * @date 2022/9/7 18:05
     */
    private void close(CloseableHttpResponse response, CloseableHttpClient httpClient) {
        if (response != null) {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            httpClient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据名称删除队列
     *
     * @param queueName         要删除的队列名称
     * @param forceDeleteFlag   是否强制删除，true：是   false：否
     * @param unUse             队列是否正在使用
     * @param emptyParam        队列参数是否为空
     * @return java.lang.Boolean
     * @author 何国发
     * @date 2022/9/8 9:46
     */
    private Boolean deleteByQueueName(String queueName, Boolean forceDeleteFlag, Boolean unUse, Boolean emptyParam) {
        boolean deleteQueueFlag = true;
        // 校验队列是否存在
        List<String> queueNameList = this.queueNameList();
        if (queueNameList.contains(queueName))
        {
            try {
                if (forceDeleteFlag)
                {
                    // 队列没有使用及没有参数就删除
                    deleteQueueFlag = rabbitAdmin.deleteQueue(queueName);
                } else {
                    rabbitAdmin.deleteQueue(queueName, unUse, emptyParam);
                }
            } catch (Exception e)
            {
                log.error("删除队列失败，失败原因：{}", e.getMessage());
                deleteQueueFlag = false;
            }
        }
        return deleteQueueFlag;
    }

}
